package org.hefan.user.service.impl;

import org.hefan.basic.exception.BusinessException;
import org.hefan.basic.service.impl.BaseServiceImpl;
import org.hefan.basic.util.MD5Utils;
import org.hefan.basic.util.StrUtils;
import org.hefan.user.constant.Constant;
import org.hefan.user.domain.Logininfo;
import org.hefan.user.domain.User;
import org.hefan.user.dto.UserDto;
import org.hefan.user.mapper.LogininfoMapper;
import org.hefan.user.mapper.UserMapper;
import org.hefan.user.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;

    /**
     * pom.xml导入了redis,就可以直接注入redisTemplate对象.
     */
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    /**
     * 发送验证码
     * @param phone
     */
    @Override
    @Transactional
    public void sendSms(String phone) {
        // 验证 = 空值验证 + 是否注册过的验证
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
        // 通过电话号找到user用户
        User user = userMapper.findByPhone(phone);
        // 如果用户不为空,说明找到了,说明账号已经注册过
        if (user != null) {
            throw new BusinessException("该号码已经注册，请直接登录!!!");
        }

        // key：业务键:15047877872(电话号)
        // value：code:时间戳

        //获取redis中保存的验证码   REGISTER_CODE_PREFIX注册时验证码的业务前缀register:
        // 通过key：业务键:15047877872(电话号) 获取 value：code:时间戳
        // obj就是value：  code:时间戳
        Object obj = redisTemplate.opsForValue().get(Constant.REGISTER_CODE_PREFIX + phone);
        // Constant.REGISTER_CODE_PREFIX     register:  业务键
        // phone    15047877872
        // Constant.REGISTER_CODE_PREFIX + phone
        // register:15047877872
        String code = null;
        if (obj != null) { // value：  code:时间戳 不为空,获取到了验证码,表示验证码没有过期
            //获取redis中以前保存的验证码
            // obj就是value：  code:时间戳
            code = obj.toString().split(":")[0]; // code:时间戳  下标0是code
            //获取以前保存的时间
            String timeString = obj.toString().split(":")[1]; // code:时间戳  下标1是时间戳
            // 如果系统时间减去上面获取的时间戳时间没有超过60000毫秒,则表示用户点了获取时间没有超过一分钟
            // Long.parseLong() 把字符串类型数字转换成long类型数字
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1 * 60 * 1000) {
                throw new BusinessException("不能重复发送验证码");
            }
        } else { // value：  code:时间戳 为空,没有获取到验证码,表示验证码过期了 或 第一次发
            // 重新生成验证码
            // 调用工具类方法发送验证码
            code = StrUtils.getRandomString(4);
        }

        // 设置 key: Constant.REGISTER_CODE_PREFIX + phone   register:15047877872
        // value: code + ":" + System.currentTimeMillis()    code:时间戳
        // 设置三分钟的有效期
        redisTemplate.opsForValue().set(Constant.REGISTER_CODE_PREFIX + phone,
                code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);

        // 通过中国网建发送短信,花钱
        //SmsUtil.sendMsg(phone,"你的验证码是：" + code + ",请在3分钟之内使用");

        // 模拟发送短信,不花钱白嫖
        System.out.println("你的验证码是：" + code + ",请在3分钟之内使用");
    }

    @Override
    @Transactional
    public void phoneRegister(UserDto userDto) {
        String phone = userDto.getPhone();
        String verifycode = userDto.getVerifycode();
        String password = userDto.getPassword();
        String rePassword = userDto.getRePassword();

        //1.校验
        //1.1.空值校验 - StringUtils.isEmpty()
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifycode)
                || StringUtils.isEmpty(password)
                || StringUtils.isEmpty(rePassword)) {
            throw new BusinessException("请输入正确的数据");
        }
        //1.2.两次密码是否相同 - equals()
        if (!password.equals(rePassword)) {
            throw new BusinessException("两次密码不一致,请重新输入!!!");
        }
        //1.3.验证码是否过期 - redis【null】
        Object obj = redisTemplate.opsForValue().get(Constant.REGISTER_CODE_PREFIX + phone);
        if (obj == null) {
            throw new BusinessException("验证码无效，请重新获取!!!");
        }
        //1.4.验证码是否正确 - redis的验证码与前端传递过来的验证🐎【忽略大小写】
        String codeTmp = obj.toString().split(":")[0];
        if (!codeTmp.equals(verifycode)) {
            throw new BusinessException("请输入正确的验证码!!!");
        }
        //1.5.手机号码是否已经被注册了
        // 通过电话号找到user用户
        User userTmp = userMapper.findByPhone(phone);
        // 如果用户不为空,说明找到了,说明账号已经注册过
        if (userTmp != null) {
            throw new BusinessException("该号码已经注册，请直接登录!!!");
        }

        //2.保存数据
        //2.1.先保存t_logininfo
        User user = userDto2User(userDto);
        Logininfo logininfo = user2Logininfo(user);

        logininfoMapper.save(logininfo);
        //2.2.再保存t_user
        user.setLogininfo_id(logininfo.getId());

        userMapper.save(user);
    }

    /**
     * 绑定发送手机验证码
     * @param phone
     */
    @Override
    public void sendBinderCode(String phone) {
        // 验证 = 空值验证 + 是否注册过的验证
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
        // 通过电话号找到user用户
        User user = userMapper.findByPhone(phone);
        // 如果用户不为空,说明找到了,说明账号已经注册过
//        if (user != null) {
//            throw new BusinessException("该号码已经注册，请直接登录!!!");
//        }

        // key：业务键:15047877872(电话号)
        // value：code:时间戳

        //获取redis中保存的验证码   REGISTER_CODE_PREFIX注册时验证码的业务前缀register:
        // 通过key：业务键:15047877872(电话号) 获取 value：code:时间戳
        // obj就是value：  code:时间戳
        Object obj = redisTemplate.opsForValue().get(Constant.BINDER_CODE_PREFIX + phone);
        // Constant.REGISTER_CODE_PREFIX     register:  业务键
        // phone    15047877872
        // Constant.REGISTER_CODE_PREFIX + phone
        // register:15047877872
        String code = null;
        if (obj != null) { // value：  code:时间戳 不为空,获取到了验证码,表示验证码没有过期
            //获取redis中以前保存的验证码
            // obj就是value：  code:时间戳
            code = obj.toString().split(":")[0]; // code:时间戳  下标0是code
            //获取以前保存的时间
            String timeString = obj.toString().split(":")[1]; // code:时间戳  下标1是时间戳
            // 如果系统时间减去上面获取的时间戳时间没有超过60000毫秒,则表示用户点了获取时间没有超过一分钟
            // Long.parseLong() 把字符串类型数字转换成long类型数字
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1 * 60 * 1000) {
                throw new BusinessException("不能重复发送验证码");
            }
        } else { // value：  code:时间戳 为空,没有获取到验证码,表示验证码过期了 或 第一次发
            // 重新生成验证码
            // 调用工具类方法发送验证码
            code = StrUtils.getRandomString(4);
        }

        // 设置 key: Constant.REGISTER_CODE_PREFIX + phone   register:15047877872
        // value: code + ":" + System.currentTimeMillis()    code:时间戳
        // 设置三分钟的有效期
        redisTemplate.opsForValue().set(Constant.BINDER_CODE_PREFIX + phone,
                code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);

        // 通过中国网建发送短信,花钱
        //SmsUtil.sendMsg(phone,"你的验证码是：" + code + ",请在3分钟之内使用");

        // 模拟发送短信,不花钱白嫖
        System.out.println("你的绑定验证码是：" + code + ",请在3分钟之内使用");
    }

    /**
     * 手机验证码登陆发送验证码
     * @param phone
     */
    @Override
    public void smsCodeByPhone(String phone) {
        // 验证 = 空值验证 + 是否注册过的验证
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
//        // 通过电话号找到user用户
//        User user = userMapper.findByPhone(phone);
//        // 如果用户不为空,说明找到了,说明账号已经注册过
//        if (user != null) {
//            throw new BusinessException("该号码已经注册，请直接登录!!!");
//        }

        Object obj = redisTemplate.opsForValue().get(Constant.PHONE_LOGIN_CODE_PREFIX + phone);
        String code = null;
        if (obj != null) { // value：  code:时间戳 不为空,获取到了验证码,表示验证码没有过期
            code = obj.toString().split(":")[0]; // code:时间戳  下标0是code
            String timeString = obj.toString().split(":")[1]; // code:时间戳  下标1是时间戳
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1 * 60 * 1000) {
                throw new BusinessException("不能重复发送验证码");
            }
        } else { // value：  code:时间戳 为空,没有获取到验证码,表示验证码过期了 或 第一次发
            code = StrUtils.getRandomString(4);
        }
        redisTemplate.opsForValue().set(Constant.PHONE_LOGIN_CODE_PREFIX + phone,
                code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);
        System.out.println("你的验证码是：" + code + ",请在3分钟之内使用");
    }

    private User userDto2User(UserDto userDto) {
        User user = new User();
        user.setUsername(userDto.getPhone());
        user.setPhone(userDto.getPhone());
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5(userDto.getPassword() + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);

        return user;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        return logininfo;
    }
}
